package net.cloudsun.graph.group;

import net.cloudsun.graph.puzzle.Pair;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

/**
 * 有限元群
 * created at 23/11/2021
 *
 * @author 俞建波
 * <a href="mailto://yujianbo@chtwm.com">yujianbo@chtwm.com</a>
 * @since 1.1.0
 */
public class FiniteGroup<T> {

    private List<T> elements;
    /**
     * 运算单位元
     */
    private T meta;
    /**
     * 正逆运算符对
     */
    private Pair<Function<T,T>> operators;

    public void buildGroup() {
        // 以5为中心的子群 文字表示为4
        final List<T> states = new ArrayList<>();
        for (T start = this.getMeta();
             !states.contains(start);
             start = this.getOperators().getA().apply(start)) {
            states.add(start);
        }
        this.elements = states;
    }
    public List<T> getElements() {
        return elements;
    }

    public void setElements(List<T> elements) {
        this.elements = elements;
    }

    public T getMeta() {
        return meta;
    }

    public void setMeta(T meta) {
        this.meta = meta;
    }

    public Pair<Function<T, T>> getOperators() {
        return operators;
    }

    public void setOperators(Pair<Function<T, T>> operators) {
        this.operators = operators;
    }

    /**
     * 自我调整
     */
    public void adjust(Comparator<? super T> comparator) {
        // 找出最小的元素
        int index = getMetaIndex(comparator);
        final ArrayList<T> list = new ArrayList<>();
        list.addAll(elements.subList(index, elements.size()));
        list.addAll(elements.subList(0, index));
        this.elements = list;
    }

    protected int getMetaIndex(Comparator<? super T> comparator) {
        final Optional<T> min = this.elements.stream().min(comparator);
        this.meta = min.orElse(meta);
        // 找出meta所在的index
        int index = 0;
        for (int i = 0; i < elements.size(); i++) {
            if (meta.equals(elements.get(i))) {
                index = i;
                break;
            }
        }
        return index;
    }
}
